<!DOCTYPE html>
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta charset="utf-8">
    <title>Beware! Floating pies!</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="">
    <meta name="author" content="">
    <script type="text/javascript" src="js/vendor/jquery-1.8.2.min.js"></script>
    <script type="text/javascript" src="js/jQSparql.js"></script>
    <script type="text/javascript" src="js/d3.js"></script>
    <script type="text/javascript" src="http://twitter.github.com/bootstrap/assets/js/bootstrap-tooltip.js"></script>
    <!-- CSS -->
    <link href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css" rel="stylesheet">
    <style type="text/css">

      /* Sticky footer styles
      -------------------------------------------------- */

      html,
      body {
        height: 100%;
        /* The html and body elements cannot have any padding or margin. */
      }

      /* Wrapper for page content to push down footer */
      #wrap {
        min-height: 100%;
        height: auto !important;
        height: 100%;
      }
      
      .container {
    width:100%;
    position:absolute;              
    min-height:100%; !important /* browser fill */
    height:auto;
	  }
	  
#svg { user-select: none; }

#title {
   -webkit-text-stroke-width: 1px;
   -webkit-text-stroke-color: white;
	position: absolute;
    top: 10px;
    left: 20px;
	z-index:1;
	-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
}

.link {
  stroke: #000;
  stroke-width: 1.5px;
}

.tip {
	user-select: none;
	fill: #000000;
	stroke: #000000;
	font-family: sans-serif;
	font-size: 12px;
	stroke-width: 0.5;
}

.details {
  color:black;
  font-size: 10px;
  font-weight: bold;
  background-color:rgba(255,255,255,1);
  padding: 10px;
  border-radius: 8px;
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
  position: relative;
 font-family: sans-serif;
}


.text {
  fill: #ffffff;
  stroke: #ffffff;
  pointer-events: none;
  font-family: sans-serif;
  user-select: none;
}

.label {
  stroke: #000000;
  stroke-width: 0.2;
  pointer-events: none;
  font-family: sans-serif;
  user-select: none;
}

.node:hover .text {
   fill: #E0E0E0;
   stroke: #E0E0E0;
}

.graph {
 fill: #FC425A;   
}


path.link {
  fill: none;
  stroke: #666;
  stroke-width: 1.5px;
}

marker#licensing {
  fill: green;
}

path.link.licensing {
  stroke: green;
}

path.link.resolved {
  stroke-dasharray: 0,2 1;
}

.node {
  
  stroke: #000;
  stroke-width: 1px;
    cursor: default;
}

.endpoint {
	stroke: white;
	stroke-width: 1px;
    cursor: default;
    user-select: none;
}

.button { display: block;}

  </style>
  


<script type='text/javascript'>

$(document).ready(function() {

		
var endpoint = "http://data.aalto.fi/sparql";
var sparql = new jQSparql();
sparql.addPrefix("aiiso","http://purl.org/vocab/aiiso/schema#");
var prefix = sparql.prefix();

var posX;
var posY;

$("#svg").mousemove(function(event) {
  posX = event.pageX;
  posY = event.pageY;
});

var width = $("#svg").width(),
    height = $("#svg").height();
 


var color = d3.scale.category10();

var nodes = [],
    links = [],
    hNodes = [],
    hLinks = [];

 var tooltip = d3.select("#svg")
    .append("div")
    .attr("id","tooltip")
     .attr("class","details")
    .style("position", "absolute")
    .style("visibility", "hidden");




var force = d3.layout.force()
    .friction(0.5)
    .gravity(0.1)
    .charge(-6000)
    .linkDistance(300)
    .linkStrength(1)
    .size([width, height])
    .on("tick", tick);

var svg = d3.select("#svg").append("svg")
    .attr("width", width)
    .attr("height", height)
    .attr("pointer-events", "all")
  .append('g')
    .call(d3.behavior.zoom().on("zoom", redraw))
  .append('g');
  

var defs = svg.append("svg:defs");

defs.append("svg:marker")
		    .attr("id", "arrow")
		    .attr("viewBox", "0 -5 10 10")
		    .attr("refX", 25)
		    .attr("refY", -10)
		    .attr("markerWidth", 4)
		    .attr("markerHeight", 4)
		    .attr("class","marker")
		    .attr("orient", "auto")
		    .append("svg:path")
		    .attr("d", "M0,-5L10,0L0,5");




var node, link, path;

svg.append('rect')
    .attr('width', width*2000)
    .attr('height', height*2000)
    .attr('fill', 'white')
    .attr("x",-2000) // Ugly hack
    .attr("y",-2000);



function redraw() {
  svg.attr("transform",
      "translate(" + d3.event.translate + ")"
      + " scale(" + d3.event.scale + ")")

}

var classes = [];
var properties = [];

var endpoints = ["http://data.aalto.fi/sparql","http://data.open.ac.uk/query","http://data.uni-muenster.de/sparql"];

for(i in endpoints) nodes.push({id:endpoints[i],name:endpoints[i],type:"endpoint"})

start();

sparql.multiQuery(endpoints, "SELECT ?sc (count(?s) as ?c) WHERE { ?s a ?sc  FILTER(!STRSTARTS(STR(?sc), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#')) FILTER(!STRSTARTS(STR(?sc), 'http://www.w3.org/2000/01/rdf-schema#')) FILTER(!STRSTARTS(STR(?sc), 'http://www.w3.org/2002/07/owl#'))  } GROUP BY ?sc","sproxy.php?service-uri=").done(function(responses) {

for(r in responses) {
	console.log(responses[r].endpoint);
	console.log(responses[r].data);
	var data = responses[r].data;
	var endpoint = responses[r].endpoint;
    for(i in data.results.bindings) {
	  var sameClass = $.grep($(classes), function(e){ return e.id == data.results.bindings[i].sc.value; });
	  if(sameClass.length == 0) {
		  classes.push({data: new Array({label:endpoint,value:parseInt(data.results.bindings[i].c.value)}), id: data.results.bindings[i].sc.value, name:sparql.prefixify(data.results.bindings[i].sc.value,sparql.lookup),type:"class",x:0,y:0});
	  } else { 
		  sameClass[0].data.push({label:endpoint,value:parseInt(data.results.bindings[i].c.value)});
		  }
	  
	}
}

var same = $.grep($(classes), function(e){ return e.data.length>1});
//var same = classes;

var other = $.grep($(classes), function(e){ return e.data.length==1});

for(i in other) {
hNodes.push(other[i]); 
var d = $.grep(nodes, function(e){ return e.id == other[i].data[0].label })[0];
hLinks.push({source:d,target:other[i],id:d.id,name:"uses class"});
 }					  			  

 	
for(i in same) {
nodes.push(same[i]);
for(x in same[i].data) {
	var d = $.grep(nodes, function(e){ return e.id == same[i].data[x].label })[0];
	var l = {source:d,target:same[i],id:d.id,name:"uses class"};
	//if(same[i].data.length>1) console.log(l);
	links.push(l);
}
}


 /*
 	var d = $.grep(nodes, function(e){ return e.id == endpoint })[0];
	var rxy = randXY(d.x,d.y);
        
        var results = $.grep($(nodes), function(e){ return e.id == data.results.bindings[i].sc.value; });
        var node = null; 
        
         if(results.length == 0) {
		
			node = {data: new Array({label:endpoint,value:parseInt(data.results.bindings[i].c.value)}),endpoint:endpoint, id: data.results.bindings[i].sc.value, name:sparql.prefixify(data.results.bindings[i].sc.value,sparql.lookup),type:"class",x:rxy.x,y:rxy.y}; 
			nodes.push(node);

	     } else { node = results[0];
          	     
	      node.data.push({label:this.e,value:parseInt(data.results.bindings[i].c.value)});
	      node.endpoint = d.id
	      
	     }
	     
        nodes.push(node);
        links.push({source:d,target:node,id:"endpoint",name:"uses class"});
*/


start();

});



/*
SELECT ?p ?oc (count(?p) as ?count) WHERE { ?s a <"+d.id+"> . ?s ?p ?o . ?o a ?oc } GROUP BY ?oc ?p
*/
function getPropertyUsages(d) {
	console.log("Querying object property usage: ");
	var endpoints = [];
	for(e in d.data) {
		endpoints.push(d.data[e].label);
	}
	console.log(endpoints);
// FILTER(!STRSTARTS(STR(?p), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#')) FILTER(!STRSTARTS(STR(?p), 'http://www.w3.org/2000/01/rdf-schema#')) FILTER(!STRSTARTS(STR(?p), 'http://www.w3.org/2002/07/owl#'))
  sparql.multiQuery(endpoints, "SELECT ?p ?oc (count(?p) as ?c) WHERE { ?s a <"+d.id+"> . ?s ?p ?o . ?o a ?oc  } GROUP BY ?p ?oc ","sproxy.php?service-uri=").done(function(responses) {
    
    for(r in responses) {
	console.log(responses[r].endpoint);
	console.log(responses[r].data);
	var data = responses[r].data;
	var endpoint = responses[r].endpoint;
	
    if(data.results.bindings!=undefined && data.results.bindings[0].p!=undefined) {
    
    for(i in data.results.bindings) {
		
	  var sameProperty = $.grep($(properties), function(e){ return e.id == data.results.bindings[i].p.value+data.results.bindings[i].oc.value; });
	  
	  var oc = $.grep($(nodes), function(e){ return e.id == data.results.bindings[i].oc.value; });
	  
	 if(oc.length!=0) {
		
	 var offset = $.grep($(properties), function(e){  return e.source == d && e.target == oc[0] }).length;	
		  
	  if( sameProperty.length == 0) {
		  properties.push({offset: offset, source: d, target: oc[0], data: new Array({label:endpoint,value:parseInt(data.results.bindings[i].c.value)}), id: data.results.bindings[i].p.value+data.results.bindings[i].oc.value, name:sparql.prefixify(data.results.bindings[i].p.value,sparql.lookup),type:"refObject"});
	  } else { 
		  sameProperty[0].offset = offset;
		  sameProperty[0].data.push({label:endpoint,value:parseInt(data.results.bindings[i].c.value)});
		  }
		  
		
		  	  
	 }
		  
 }}
}


for(i in properties) {
	
	links.push(properties[i]);
	
}

start();

});

}


function getPropertyUsage(d) {
  sparql.query(d.endpoint, "SELECT DISTINCT ?p ?oc WHERE { ?s a <"+d.id+"> . ?s ?p ?o . ?o a ?oc } ").done(function(data) {
    for(i in data.results.bindings) {
        var rxy = randXY(d.x,d.y);
        var results = $.grep(nodes, function(e){ return e.id == data.results.bindings[i].oc.value; });

        
        var oc = null;
        
        if(results.length == 0) {
			oc = {graph: d.graph, endpoint: d.endpoint, id: data.results.bindings[i].oc.value,name:sparql.prefixify(data.results.bindings[i].oc.value,sparql.lookup),type:"class",x:rxy.x,y:rxy.y};
			nodes.push(oc);
	     } else { oc = results[0]; }
	     
	     var doubles = $.grep(links, function(e){  return e.source == d && e.target == oc });

	     var p = {offset: doubles.length, source: d, target: oc, graph: d.graph, endpoint: d.endpoint, id: data.results.bindings[i].p.value, name:sparql.prefixify(data.results.bindings[i].p.value,sparql.lookup),type:"property"};	     
	     
	     links.push(p);
	     
    }
    
	sparql.query(d.endpoint, "SELECT ?p ?ot (count(?p) as ?c) WHERE { ?s a <"+d.id+"> . ?s ?p ?o "+filter+" } GROUP BY ?p (datatype(?o) as ?ot)").done(function(data) {
	for(i in data.results.bindings) {
		   var rxy = randXY(d.x,d.y);
		   
		   var results = $.grep(nodes, function(e){ return e.id == (data.results.bindings[i].p.value+data.results.bindings[i].ot.value)});
		   var ot = null; //{data: new Array({label:d.endpoint,value:parseInt(data.results.bindings[i].c.value)}), graph: d.graph, endpoint: d.endpoint, id: data.results.bindings[i].p.value+data.results.bindings[i].ot.value,name:sparql.prefixify(data.results.bindings[i].ot.value),type:"literal",x:rxy.x,y:rxy.y};
         
         if(results.length == 0) {


			ot = {data: new Array({label:d.endpoint,value:parseInt(data.results.bindings[i].c.value)}), graph: d.graph, endpoint: d.endpoint, id: data.results.bindings[i].p.value+data.results.bindings[i].ot.value,name:sparql.prefixify(data.results.bindings[i].ot.value),type:"literal",x:rxy.x,y:rxy.y};
			nodes.push(ot);
			
			
			var p = {source: d, target: ot, graph: d.graph, endpoint: d.endpoint, id: data.results.bindings[i].p.value, name:sparql.prefixify(data.results.bindings[i].p.value,sparql.lookup),type:"property"};	     
			links.push(p);

	     } else { 
	      node = results[0];   
	      node.data.push({label:d.endpoint,value:parseInt(data.results.bindings[i].c.value)});
	     }

         
	      
              
        }
        start();
	   });


    
    
start();
});  
	
}



function randXY(x,y) {
 var rand = Math.random();
    var ag = rand * Math.PI * 2;
    var xl = x + Math.cos(ag) *50;
    var yl = y + Math.sin(ag) *50;  
    return {x:xl,y:yl};    
}



function start() {

      force
      .nodes(nodes)
      .links(links)
      .start();
      
    var r = 30,  // radius
    
   // color = ["#0071C1","#FC425A","#FED40C","",""];    // builtin range of colors
      color = ["#1f77b4", "#aec7e8",
  "#ff7f0e", "#ffbb78",
  "#2ca02c", "#98df8a",
  "#d62728", "#ff9896",
  "#9467bd", "#c5b0d5",
  "#8c564b", "#c49c94",
  "#e377c2", "#f7b6d2",
  "#7f7f7f", "#c7c7c7",
  "#bcbd22", "#dbdb8d",
  "#17becf", "#9edae5"];
  
    link = svg.selectAll("line").data(force.links(), function(d) { return d.source.id + "-" + d.target.id; });
        
    enter = link.enter().insert("line",".node")
            .attr("class", "link")
	  	//.attr("marker-end", "url(#arrow)")
	  	.style("stroke", function(d) {  return  color[endpoints.indexOf(d.source.id)] })

	  	 
    link.exit().remove();
  
     var arc = d3.svg.arc()
        .outerRadius(r);  
    
  node = svg.selectAll("g .node").data(force.nodes(), function(d) { return d.id;});
    /*
  on("mouseover", function(d) { return d3.select("#tooltip").style("visibility", "visible").text(d.name);})
      .on("mousemove",function(d) { return tooltip.style("top", (posY-10)+"px").style("left",(posX+10)+"px"); })
      .on("mouseout",function(d) { return d3.select("#tooltip").style("visibility", "hidden"); })
    */
    
    

    
  var g = node.enter().append("g")
      .attr("class", "node")
      .call(force.drag)
       .on("contextmenu", function(d) {
          
          var htmlString = "<h4>"+d.name+"</h4>";
		  htmlString+="<p>ID: "+sparql.unprefixify(d.name)+"</p>"
		  for(i in d.data) {
			  htmlString+="<p>"+d.data[i].value+" instances in "+d.data[i].label+"</p>"
		  }
		  
		  
		  
		  var t = d3.select("#tooltip")
		  .style("visibility", "visible")
		  .on("mouseover",function(d) { return d3.select("#tooltip").style("visibility", "visible"); })
		  .on("mouseout",function(d) { return d3.select("#tooltip").style("visibility", "hidden"); })
		  .style("top", (posY-20)+"px")
		  .style("left",(posX-20)+"px");

		  t.html(htmlString);
		  
		  /* ENDPOINT MENUS */
		  if(d.type=="endpoint") {
	          t.append("a").attr("class","button").on("click",function() {
				  // Loop all hidden nodes
				  for(i=0;i<hNodes.length;i++) {
					// Loop all endpoints
					for(f in hNodes[i].data) {
						// If there is node with the same endpoint
						if(hNodes[i].data[f].label == d.id) {
							nodes.push(hNodes[i]);
							// Loop trough all hidden links
							for(h=0;h<hLinks.length;h++) 
								if(hLinks[h].target == hNodes[i] || hLinks[h].source == hNodes[i]){
									links.push(hLinks[h]);
									hLinks.splice(h,1);
									h--;
								}
							 // Remove from hidden nodes and end this loop	
							 hNodes.splice(i,1);	
							 i--;
							 break;
							}
						  }
						}	
				  start();
			  }).text("Show all classes");
		  }
		  /* CLASS MENUS */
		  if(d.type=="class") {
			  
			  t.append("a").attr("class", "button").on("click",function() {
			  d3.select("#tooltip").style("visibility", "hidden");
			  getPropertyUsages(d);
			  }).text("Show objectProperties");
			  
			t.append("a").attr("class", "button").on("click",function() {
			  
			for(i=0;i<links.length;i++) {
				if(links[i].target == d || links[i].source == d) {
					if(links[i].type != "refObject") hLinks.push(links[i]);
					links.splice(i,1);
					i--;
				}}  
			  
			for(i=0;i<nodes.length;i++) {
				if(nodes[i] == d) {
					hNodes.push(nodes[i]);
					nodes.splice(i,1);
					i--;
				}}

			d3.select("#tooltip").style("visibility", "hidden");
			start();	  	  
			}).text("Hide");

  }

    d3.event.preventDefault();
})
      .each(function(d) {
		 if(d.data!=undefined) { 

		 var arcs = d3.select(this).selectAll("g.slice")    
        .data(d3.layout.pie().value(function(d) { return d.value; })(d.data))                        
        .enter()                          
        .append("g")          
        .attr("class", "slice");
        
		arcs.append("svg:path")
        .attr("fill", function(d) { return  color[endpoints.indexOf(d.data.label)] })
        .attr("d", arc);

     /*  
      arcs.append("svg:text")
      .attr("transform", function(d) { //set the label's origin to the center of the arc
        //we have to make sure to set these before calling arc.centroid
        d.outerRadius = r + 50; // Set Outer Coordinate
        d.innerRadius = r + 45; // Set Inner Coordinate
        return "translate(" + arc.centroid(d) + ")";
      })
      .attr("text-anchor", "middle") //center the text on it's origin
      .style("fill", "Purple")
      .style("font", "bold 12px Arial")
      .text(function(d) { console.log(d); return d.data.label; });
      */
        
	} else {
	
		var circle = d3.select(this).append("circle")
		 .attr("fill", function(d) {  return  color[endpoints.indexOf(d.id)] })
      .attr("class", function(d) { return d.type; })
	  .transition()
      .attr("r", 40)
      .attr("title", function(d) { return d.name });
		
	}
		 
	  });


// endpoint name      
/*
      g.append("text")
      .attr("class","text")
      .text(function(d) { return d.size })
      .style("font-size", "10px") // initial guess
      .attr("text-anchor", "middle")
      .attr("dy", ".3em");
  */

      g.append("text")
        .attr("class", "tip")
        .attr("dx", 0)
        .attr("dy", ".35em")
        .attr("text-anchor", "middle")
        .text(function(d) { return d.name });
            
        
    
  node.exit().remove();


path = svg.selectAll(".label").data(force.links(), function(d) { return d.source.id + "-" + d.target.id; });
	
path.enter().insert("text",".node")
	    .attr("class","label")
	    .text(function(d) { return d.name; })
	    .attr("fill", function(d) {  return  color[endpoints.indexOf(d.source.id)] })
	
path.exit().remove();



  
}

function tick() {
  node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

  link.attr("x1", function(d) { return d.source.x; })
      .attr("y1", function(d) { return d.source.y; })
      .attr("x2", function(d) { return d.target.x; })
      .attr("y2", function(d) { return d.target.y; });
      
      
path.attr("transform", function(d) 
	{
		
		
		var dx = (d.target.x - d.source.x),
		dy = (d.target.y - d.source.y);
		
		var dr = Math.sqrt(dx * dx + dy * dy);
		var sinus = dy/dr;
		var cosinus = dx/dr;
		var l = d.name.length*6;
		var offset = (1 - (l / dr )) / 2 ;
		var x=(d.source.x + dx*offset);
		var y=(d.source.y + dy*offset);
		
		if(d.offset!=undefined) {x=x+(d.offset*12); y=y+(d.offset*12); }
		
	    return "translate(" + x + "," + y + ") matrix("+cosinus+", "+sinus+", "+-sinus+", "+cosinus+", 0 , 0)";
	});
	
	

}

}); 

</script>
  
<body>
	<div id="wrapper">
      <div id="title"><h3>Shared Vocabulary</h3></div>
      <div id="svg" class="container"></div>
   </div>
</body>
</html>
